#include<iostream>
#include "log.hpp"
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "task.hpp"

extern Log lg;

class Tcpserver
{
public:
    Tcpserver(uint16_t port,string ip="0.0.0.0",int backlog=10)
        :_port(port)
        ,_ip(ip)
        ,_backlog(backlog)
    {}
    void Start()
    {
        //1.创建套接字
        _listenfd=socket(AF_INET,SOCK_STREAM,0);
        if(_listenfd<0)
        {
            lg(Fatal, "error socket: %s, error code: %d", strerror(errno), errno);
            exit(-1);
        }
        lg(Info, "socket success: %s, error code: %d", strerror(errno), errno);

        //2.bind连接
        struct sockaddr_in local;
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        // struct in_addr ipbuffer;
        // inet_aton(_ip.c_str(),&ipbuffer);
        // local.sin_addr=ipbuffer;
        local.sin_addr.s_addr=inet_addr(_ip.c_str());
        socklen_t len=sizeof(local);
        int n1=bind(_listenfd,(const struct sockaddr*)&(local),len);
        if(n1<0)
        {
            lg(Fatal, "error bind: %s, error code: %d", strerror(errno), errno);
            exit(-2);
        }
        lg(Info, "bind success: %s, error code: %d", strerror(errno), errno);
        //3.listen监听是否有连接请求 ,只能被动连接客户端
        //backlog：全连接队列的最大长度。如果有多个客户端同时发来连接请求，
        //此时未被服务器处理的连接就会放入连接队列，该参数代表的就是这个全连接队列的最大长度，
        //一般不要设置太大，设置为5或10即可
        int n2=listen(_listenfd,_backlog);
        if(n2<0)
        {
            lg(Fatal, "error listen: %s, error code: %d", strerror(errno), errno);
            exit(-3);
        }
        lg(Info, "listen success: %s, error code: %d", strerror(errno), errno);
    }
    void Run()
    {
        //三次握手完成后，accept()才会返回建立连接
        //如果没有用户建立连接，accpet()会阻塞等待
        //上面的socket()得到的文件描述符相当于只把连接客户端引入连接（这个只能有一个）
        //但是真正给客户端提供服务的是accept()返回的文件描述符，并且可以有多个
        while(1)
        {
            struct sockaddr_in client;
            socklen_t len=sizeof(client);
            int sockfd=accept(_listenfd,(struct sockaddr*)&client,&len);
            if(sockfd<0)
            {
                lg(Fatal, "error socket: %s, error code: %d", strerror(errno), errno);
                exit(-3);
            }
            char clientip[20];
            inet_ntop(AF_INET,&(client.sin_addr),clientip,sizeof(clientip));
            uint16_t clientport=ntohs(client.sin_port);
            lg(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, clientip, clientport);
            //创建任务服务
            //字典翻译  //用完即退出任务
           
            task t(sockfd,clientip,clientport); 

            //服务完后关闭文件描述符
            t.Run();

        }
    }

private:
    int _listenfd;
    uint16_t _port;
    string _ip;
    int _backlog;
};